package learm.pers.studypdf.pdf.utils;

import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/*
 * <p><标题>：通用帮助类</p>
 * <p><描述>：</p>
 * @author: fudl
 * @time: 3/26/2020 11:21 AM
 */
@Slf4j
public abstract class CommonUtil {

    private static String ENCODER = "UTF-8";



    /**
     * 验证对象是否为NULL,空字符串，空数组，空的Collection或Map(只有空格的字符串也认为是空串)
     *
     * @param obj 被验证的对象
     * @param message 异常信息
     */
    @SuppressWarnings("rawtypes")
    public static void notEmpty(Object obj, String message) {
        if (obj == null) {
            throw new IllegalArgumentException(message + " 必须存在！");
        }
        if (obj instanceof String && obj.toString().trim().length() == 0) {
            throw new IllegalArgumentException(message + " 必须存在！");
        }
        if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
            throw new IllegalArgumentException(message + " 必须存在！");
        }
        if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
            throw new IllegalArgumentException(message + " 必须存在！");
        }
        if (obj instanceof Map && ((Map) obj).isEmpty()) {
            throw new IllegalArgumentException(message + " 必须存在！");
        }
    }


    /**
     * 验证对象是否为NULL,空字符串，空数组，空的Collection或Map(只有空格的字符串也认为是空串)
     *
     * @param obj 被验证的对象
     */
    public static boolean isNotEmpty(Object obj) {
        try {
            notEmpty(obj, "");
        } catch (IllegalArgumentException e) {
            return false;
        }
        return true;
    }


    /**
     * 去除请求空字段
     *
     * @param params 请求参数集合
     */
    public static Map<String, String> removeBlankRequest(Map<String, String> params) {
        Map<String, String> reqMap = new HashMap<>();
        reqMap.putAll(params);
        Set<String> set = params.keySet();
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (StringUtils.isBlank(String.valueOf(params.get(key)))) {
                reqMap.remove(key);
            }
        }
        return reqMap;
    }

    /**
     * 获取用户真实IP地址，不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
     * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值，究竟哪个才是真正的用户端的真实IP呢？
     * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
     *
     * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
     *
     * 用户真实IP为： 192.168.1.110
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }



    /**
     * 生成请求URL
     * 格式：a=1&b=2&c=77
     *
     * @param params 请求参数集合
     */
    public static String generaterRequestUrl(Map<String, String> params)
        throws UnsupportedEncodingException {
        notEmpty(params, "生成签名的参数集合为空");
        Set<String> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = String.valueOf(value);
            temp.append(URLEncoder.encode(valueString, ENCODER));
        }
        return temp.toString();
    }

    /**
     * 将servletRequest转换为map（value为空的删除）
     */
    public static Map<String, String> getAllRequestParam(HttpServletRequest request) {
        return getAllRequestParam(request, ENCODER);
    }

    /**
     * 将servletRequest转换为map（value为空的删除）
     * request.getParameter接收postl参数，发送端content Type必须设置为application/x-www-form-urlencoded
     * request的json格式请求该方法无法获取
     */
    @SuppressWarnings("rawtypes")
    public static Map<String, String> getAllRequestParam(HttpServletRequest request,
        String encoder) {

        Map<String, String> values = new HashMap<>();
        try {
            request.setCharacterEncoding(Optional.ofNullable(encoder)
                .filter(x -> StringUtils.isNotBlank(x))
                .orElse("ISO-8859-1"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            log.error("不支持[{}]的编码转换", encoder);
        }

        Enumeration enums = request.getParameterNames();
        while (enums.hasMoreElements()) {
            String paramName = (String) enums.nextElement();
            String paramValue = request.getParameter(paramName);
            if (StringUtils.isNotBlank(paramValue)) {
                values.put(paramName, paramValue);
            }
        }
        return values;
    }

    /**
     * 是否有效的NUMBER类型
     *
     * @return boolean
     */
    public static boolean isValidNumberValue(Number id) {
        if (id == null) {
            return false;
        }
        if (id instanceof Integer && id.intValue() >= 0) {
            return true;
        }
        if (id instanceof Double && id.intValue() >= 0) {
            return true;
        }
        if (id instanceof Long && id.longValue() >= 0) {
            return true;
        }
        log.warn("ID=[{}]不是有效的数字型");
        return false;

    }

    public static <K, V> Map<K, V> convert2Map(List<V> sourceList, String keyName,
        Class<K> keyClass) {
        Map<K, V> map = new HashMap<K, V>();

        if (sourceList == null || sourceList.isEmpty()) {
            return map;
        }
        for (V value : sourceList) {
            BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(value);
            beanWrapper.setAutoGrowNestedPaths(true);
            K key = keyClass.cast(beanWrapper.getPropertyValue(keyName));
            if (key == null) {
                continue;
            }
            map.put(key, value);
        }

        return map;
    }

    public static String readableFileSize(long size) {
        if (size <= 0) {
            return "0";
        }
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " "
            + units[digitGroups];
    }




    public static void main(String[] args) {
        // getParamterName(CommonUtil.class, null)
        //     .forEach(System.out::println);

    }


    public static Map countRecoverlist(List<String> list) {
        Map<String,Integer> map = new HashMap<>();
        for(String str:list){
            Integer i = 1; //定义一个计数器，用来记录重复数据的个数
            if(map.get(str) != null){
                i=map.get(str)+1;
            }
            map.put(str,i);
        }
        return map;
    }

    /**
     * 验证身份证真假
     * @param  carNumber 身份证号
     * @return boolean*/
    public static boolean isCard(String carNumber) {
        if(StringUtils.isBlank(carNumber)){
            return false;
        }
        //判断输入身份证号长度是否合法
        if (carNumber.length() != 18) {
            return false;//不合法 抛出一个异常
        }
        //校验身份证真假
        int sum = 0;
        int[] weight = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};//将加权因子定义为数组
        //遍历weight数组 求身份证前17项系数和
        for (int i = 0; i < weight.length; i++) {
            int n = carNumber.charAt(i) - 48;//获取 身份证对应数
            int w = weight[i];
            sum += w * n;
        }
        //对11求余
        int index = sum % 11;
        //校验码
        String m = "10X98765432";
        //获取身份证最后一位进行比对
        return m.charAt(index) == carNumber.charAt(17);
    }


    public static boolean isCard1(String cardcode) {
        if (cardcode.length() > 12) {
            //第一代身份证正则表达式(15位)
            String isIDCard1 = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$";
            //第二代身份证正则表达式(18位)
            String isIDCard2 ="^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])((\\d{4})|\\d{3}[A-Z])$";
            //验证身份证
            if (cardcode.matches(isIDCard1) || cardcode.matches(isIDCard2)) {
                return true;
            }
            return false;
        }else{
            return true;
        }
    }

    /**
     * 获取百分比工具类
     */
    public static String percentageConversion(int divisor, int dividend) {
        String percentage = "";// 接受百分比的值
        double y = divisor * 1.0;
        double z = dividend * 1.0;
        if (y == 0 || z == 0) {
            return "0%";
        }
        double result = y / z;

        DecimalFormat decimalFormat = new DecimalFormat("##.00%"); // ##.00%

        percentage = decimalFormat.format(result);
        // ##.00% 使用这种转换方式，整数位如果是0 则会被删除  即0.35% 会出现 .35%的情况
        char c = percentage.charAt(0);
        if (String.valueOf(c).equals(".")) {
            StringBuffer sb = new StringBuffer();
            sb.append("0").append(percentage);
            return String.valueOf(sb);
        }
        return percentage;
    }

}
